package com.ruoyi.common.config.pay;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.locks.ReentrantLock;

public class OrderIdGenerator {
    public static SimpleDateFormat IdDate = new SimpleDateFormat("yyyyMMddHHmmssSSS");
    private final static long groupIdBits = 5L;// 生成器组ID位数
    private final static long maxId = -1L ^ (-1L << groupIdBits);// 生成器ID最大值
    private final static long maxGroupId = -1L ^ (-1L << groupIdBits);// 生成器组ID最大值
    private final static long sequenceBits = 12L;// 毫秒内自增位
    private final static long sequenceMask = -1L ^ (-1L << sequenceBits);// 自增ID掩码
    private ReentrantLock lock = new ReentrantLock();
    /**
     * 为了避免并发阻塞，每个线程一个实例
     */
    private static ThreadLocal<OrderIdGenerator> defaultIdGenerator=new ThreadLocal<OrderIdGenerator>();

    private final long databaseId;
    private final long dbGroupId;
    private static long lastTimestamp = 1L;
    private long sequence = 0L;
    public static OrderIdGenerator getDefault(){
        if(defaultIdGenerator.get()==null){
            defaultIdGenerator.set(new OrderIdGenerator(Thread.currentThread().getId()%maxGroupId, Thread.currentThread().getId()%maxId));
        }
        return defaultIdGenerator.get();
    }

    public OrderIdGenerator(long groupId, long id) {
        if (id > maxId || id < 0) {
            throw new IllegalArgumentException("Id不能大于%d或小于0");
        }
        if (groupId > maxGroupId || groupId < 0) {
            throw new IllegalArgumentException("集群Id不能大于%d或小于0");
        }
        this.databaseId = id;
        this.dbGroupId = groupId;
    }

    public String nextId() {
        lock.lock();
        try {
            long timestamp = timeGen();
            if (timestamp < lastTimestamp) {
                throw new RuntimeException("系统时间倒退 "
                        + (lastTimestamp - timestamp) + "毫秒秒，不允许生成id。");
            }
            if (lastTimestamp == timestamp) {
                // 当前毫秒内，则+1
                sequence = (sequence + 1) & sequenceMask;
                if (sequence == 0) {
                    // 当前毫秒内计数满了，则等待下一毫秒
                    timestamp = toNextMillis(lastTimestamp);
                }
            } else {
                sequence = 0;
            }
            lastTimestamp = timestamp;
            int treeRandom=(int)(Math.random()*900)+100;
            String nextId = timestamp+""+treeRandom+""+sequence;
            return nextId;
        } finally {
            lock.unlock();
        }
    }
    private long toNextMillis(final long lastTimestamp) {
        long timestamp = this.timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = this.timeGen();
        }
        return timestamp;
    }

    private long timeGen() {
        String nowTime =getNowTime();
        return Long.parseLong(nowTime);
    }

    public static String getNowTime(){
        Date date =new Date();
        return IdDate.format(date);
    }
}
